function GM:PlayerInitialSpawn(ply)	
	ply:SetAFK(false)
	ply:PrintMessage(HUD_PRINTTALK, "This server is running RPDM (Basewars)") 
	ply:PrintMessage(HUD_PRINTTALK, "PRESS F1 TO READ THE RULES, HELP, AND STATS.")
	
	ply:SetTeam(1)
	ply.Class = ply:GetTeamClass()
	ply:SetNWString("job", ply.Class.Name)
	timer.Create(ply:UniqueID() .. "jobtimer", 60/*pay day time*/, 0, ply.GiveMoney, ply, ply.Class.Pay)
end

function GM:PlayerSetModel(ply)
	local selectedmodelshort = ply:GetInfo("cl_playermodel")
	local selectedmodel = player_manager.TranslatePlayerModel(selectedmodelshort)

	if table.HasValue(ply.Class.Models, selectedmodelshort) then
		ply:SetModel(selectedmodel)
	else
		ply:SetModel(player_manager.TranslatePlayerModel(table.Random(ply.Class.Models)))
	end
end

function GM:PlayerSpawn(ply)
	ply.SpawnedTime = CurTime() //workaround required for PlayerCanPickupWeapon
	
	if ValidEntity(ply.Spawnpoint) then
		ply:SetPos(ply.Spawnpoint:GetPos() + Vector(0, 0, 16))
	end
	
	self:PlayerSetModel(ply)
	self:PlayerLoadout(ply)
end

function GM:PlayerLoadout(ply)	
	ply:SetHealth(ply.Class.Health)
	ply:SetMaxHealth(ply.Class.Health)
	ply:SetArmor(ply.Class.Armor)
	ply:ExitVehicle()
	ply:StripWeapons()
	ply:RemoveAllAmmo()
	ply:Give("weapon_physcannon")
	ply:Give("gmod_tool")
	ply:Give("weapon_physgun")

	for weapon, upgraded in pairs(ply.Class.LoadoutWeps) do
		ply:Give(weapon)
		if upgraded then
			ply:GetWeapon(weapon):SetUpgrade(1)
		end
	end	
	for ammotype, amount in pairs(ply.Class.LoadoutAmmo) do
		ply:GiveAmmo(amount, ammotype)
	end
end

//changes the behavior of Use so a player
//must be looking directly at the entity
function GM:PlayerUse(ply, ent)
	local tr = ply:GetEyeTraceNoCursor()
	if tr.Entity && !tr.HitWorld then
		return true
	else
		return false
	end
end

//workaround required for PlayerCanPickupWeapon
local meta = FindMetaTable("Player")
local oldgive = meta.Give
function meta:Give(wep)
	self.SpawnedTime = CurTime()
	oldgive(self, wep)
end

//workaround required for PlayerCanPickupWeapon
//might be useful somewhere else too
//some ents already have a creation time
function GM:OnEntityCreated(ent)
	if ValidEntity(ent) && !ent.Created then
		ent.Created = CurTime()
	end
end

function GM:PlayerCanPickupWeapon(ply, weapon)
	if CurTime() - ply.SpawnedTime < 0.1 && CurTime() - weapon.Created < 0.1 then
		return true
	elseif ply:KeyDown(IN_USE) then
		local tr = ply:GetEyeTraceNoCursor()
		if tr.Entity == weapon then
			return true
		end
	else
		return false
	end
end

function GM:KeyPress(ply, code)
	ply:SetAFK(false)
end

local meta = FindMetaTable("Player")
function meta:IsAllied(ply)
    return (self:GetInfoNum("rpdm_ally_pl" .. ply:EntIndex()) == 1 && ply:GetInfoNum("rpdm_ally_pl" .. self:EntIndex()) == 1)
end

function GM:DoPlayerDeath(ply, attacker, dmginfo)
	ply:CreateRagdoll()
	ply:AddDeaths(1)
	if (attacker:IsValid() && attacker:IsPlayer()) then
		if (attacker == ply) then
			attacker:AddFrags(-1)
		else
			attacker:AddFrags(1)
		end	
	end
	
	for k, wep in pairs(ply:GetWeapons()) do
		if wep.ClassName && wep.ClassName != "gmod_tool" then
			ply:DropWeapon(wep)
		end
	end
end

function GM:PlayerDeath(ply, weapon, killer)
	self:PlayerDeathNotify(ply, weapon, killer)
	
	-- This makes sure you dont have the burning sound when you die, and resets stunstick.
	ply:Ignite(0.001,0)
	ply:Extinguish()
	ply:ConCommand("pp_motionblur 0;pp_dof 0")
		
	if(ply != killer && killer:IsValid()) then
		local winrar = killer
		// in case of a backstab kill, credit the guy holding the knife.
		if (killer:IsWeapon()) then
			winrar = killer:GetOwner()
		end
		if (winrar:IsPlayer() && ply != winrar) then
				if (ply:GetNWInt("hitlist")>0) then
					local hitcash = ply:GetNWInt("hitlist")
					winrar:GiveMoney(math.ceil(hitcash))
					ply:SetNWInt("hitlist", 0)
					Notify(winrar, 2, 3, "Paid $" .. hitcash .. " for hit")
				end
		end
	end
end

function GM:PlayerAuthed(ply, SteamID)
	ply:CheckForNewPlayer()
	ply:SetDTInt(DT_INT_MONEY, ply:GetMoney())
end

function GM:PlayerDisconnected(ply)
	timer.Destroy(ply:UniqueID().. "jobtimer")
	timer.Destroy(ply:UniqueID().. "AFK")
end

function ScaleDamage( ply, hitgroup, dmginfo )
	ply:GetTable().Headshot = false	
	if (hitgroup == HITGROUP_GEAR || hitgroup == HITGROUP_GENERIC || hitgroup == HITGROUP_CHEST || hitgroup == HITGROUP_STOMACH) then
		dmginfo:ScaleDamage(1)
	end
	
	if ( hitgroup == HITGROUP_HEAD ) then
		ply:GetTable().Headshot = true
	 end
	 
	if (hitgroup == HITGROUP_LEFTARM || hitgroup == HITGROUP_RIGHTARM || hitgroup == HITGROUP_RIGHTLEG || hitgroup == HITGROUP_LEFTLEG) then
		dmginfo:ScaleDamage(0.5)
	end
end
hook.Add("ScalePlayerDamage","ScaleDamage",ScaleDamage)

function DisablePropDamage(ent, inflictor, attacker, amount, dmginfo)
	//disables prop and vehicle damage.
	if (ent:IsPlayer() && (dmginfo:IsDamageType(DMG_CRUSH) || dmginfo:IsDamageType(DMG_VEHICLE))) then
	  dmginfo:ScaleDamage(0)
	end
end
hook.Add("EntityTakeDamage","DisablePropDamage",DisablePropDamage)

function GM:PlayerDeathNotify(Victim, Inflictor, Attacker)
	if (Inflictor:GetClass()=="env_physexplosion" || Inflictor:GetClass()=="env_fire") && ValidEntity(Inflictor:GetTable().attacker) then
		Attacker = Inflictor:GetTable().attacker
	end
	// Don't spawn for at least 3 seconds
	if Inflictor==Victim && Attacker==Victim then
		Victim.NextSpawnTime = CurTime() + 5
	else
		Victim.NextSpawnTime = CurTime() + 3
	end

	// Convert the inflictor to the weapon that they're holding if we can.
	// This can be right or wrong with NPCs since combine can be holding a 
	// pistol but kill you by hitting you with their arm.
	// fuck all of this. i \dont know whats the fuck im goindgungairngjormel
	if (Inflictor && Inflictor == Attacker && (Inflictor:IsNPC() || Inflictor:IsPlayer())) then
		 Inflictor = Inflictor:GetActiveWeapon()
	else
	end
	
	// send the inflictor class independently in case the inflictor is not in client PVS
	if (Attacker == Victim) then
		if !ValidEntity(Inflictor) then Inflictor = Victim end
		umsg.Start("PlrKilledSelf")
			umsg.Entity(Victim)
			umsg.Entity(Inflictor)
			umsg.String(Inflictor:GetClass())
			umsg.Bool(Victim:GetTable().Headshot)
		umsg.End()
		MsgAll(Attacker:Nick() .. " suicided using " .. Inflictor:GetClass() .. "!\n")
		return 
	end

	if (Attacker:IsPlayer()) then
		umsg.Start("PlrKilledPlr")
			umsg.Entity(Victim)
			umsg.Entity(Inflictor)
			umsg.Entity(Attacker)
			umsg.String(Inflictor:GetClass())
			umsg.Bool(Victim:GetTable().Headshot)
		umsg.End()
		MsgAll(Attacker:Nick() .. " killed " .. Victim:Nick() .. " using " .. Inflictor:GetClass() .. "\n")
		return
	end
	
	umsg.Start("PlrKilled")
		umsg.Entity(Victim)
		umsg.Entity(Inflictor)
		umsg.String(Attacker:GetClass())
		umsg.String(Inflictor:GetClass())
		umsg.Bool(Victim:GetTable().Headshot)
	umsg.End()
	MsgAll(Victim:Nick() .. " was killed by " .. Attacker:GetClass() .. "\n")
end

function meta:SetAFK(bool)
	self:SetDTBool(DT_BOOL_AFK, bool)
	
	if !bool then
		timer.Create(self:UniqueID().. "AFK", 360/*afktime*/, 1, self.SetAFK, self, true)
	end
end

function GM:SetupPlayerVisibility(ply)
	for k,v in pairs(ents.FindByClass("bigbomb")) do
		if v:GetNWBool("armed") then
			AddOriginToPVS(v:GetPos())
		end
	end
end